package com.lixixi.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lixixi.tingshu.album.mapper.TrackInfoMapper;
import com.lixixi.tingshu.album.mapper.TrackStatMapper;
import com.lixixi.tingshu.album.properties.VodProperties;
import com.lixixi.tingshu.album.service.AlbumInfoService;
import com.lixixi.tingshu.album.service.AlbumTrackInfoService;
import com.lixixi.tingshu.common.constant.SystemConstant;
import com.lixixi.tingshu.common.result.Result;
import com.lixixi.tingshu.common.result.ResultCodeEnum;
import com.lixixi.tingshu.common.util.AuthContextHolder;
import com.lixixi.tingshu.common.util.UploadFileUtil;
import com.lixixi.tingshu.exception.BaseException;
import com.lixixi.tingshu.model.album.AlbumInfo;
import com.lixixi.tingshu.model.album.TrackInfo;
import com.lixixi.tingshu.model.album.TrackStat;
import com.lixixi.tingshu.query.album.TrackInfoQuery;
import com.lixixi.tingshu.user.api.UserApiFeignClient;
import com.lixixi.tingshu.vo.album.*;
import com.lixixi.tingshu.vo.user.UserInfoVo;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import com.tencentcloudapi.common.AbstractModel;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.vod.v20180717.VodClient;
import com.tencentcloudapi.vod.v20180717.models.DeleteMediaRequest;
import com.tencentcloudapi.vod.v20180717.models.DeleteMediaResponse;
import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest;
import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
public class AlbumTrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements AlbumTrackInfoService {
	@Autowired
	VodProperties vodProperties;

	//避免循环依赖
	@Autowired
	@Lazy
	AlbumInfoService albumInfoService;

	//注入媒体文件上传客户端对象
	@Autowired
	VodUploadClient vodUploadClient;

	@Autowired
	TrackInfoMapper trackInfoMapper;

	@Autowired
	TrackStatMapper trackStatMapper;

	@Autowired
	private UserApiFeignClient userApiFeignClient;

	//音频状态的统计类型
	final static List<String> trackStatList = List.of(SystemConstant.TRACK_STAT_PLAY
			, SystemConstant.TRACK_STAT_COLLECT
			, SystemConstant.TRACK_STAT_PRAISE
			, SystemConstant.TRACK_STAT_COMMENT);

	@Override
	public JSONObject uploadTrack(MultipartFile multipartFile) throws IOException {
		//创建收集返回的媒体信息的容器
		JSONObject trackInfoJson = new JSONObject();
		//文件上传至本地的临时媒体文件路径
		String tempPath = UploadFileUtil.uploadTempPath(vodProperties.getMediaFilePath(), multipartFile);
		//上传媒体文件, 构造上传请求对象
		VodUploadRequest request = new VodUploadRequest();
		//设置媒体本地上传路径。
		request.setMediaFilePath(tempPath);
		try
		{
			//调用上传方法，传入接入点地域及上传请求。
			VodUploadResponse response = vodUploadClient.upload("ap-guangzhou", request);
			trackInfoJson.put("mediaFileId", response.getFileId());
			trackInfoJson.put("mediaUrl", response.getMediaUrl());
			log.info("TrackInfoJson = {}", trackInfoJson);
		} catch (Exception e)
		{
			// 业务方进行异常处理
			log.error("Upload Err", e);
		}
		return trackInfoJson;
	}

	@Override
	@Transactional
	public void saveTrackInfo(TrackInfoVo trackInfoVo) {
		//vo转dto
		TrackInfo trackInfo = BeanUtil.toBean(trackInfoVo, TrackInfo.class);
		//获取媒体文件id
		String mediaFileId = trackInfo.getMediaFileId();
		//设置用户id
		trackInfo.setUserId(AuthContextHolder.getUserId());
		//设置音频来源
		trackInfo.setSource(SystemConstant.TRACK_SOURCE_USER);
		//设置音频审核状态
		trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
		//根据媒体文件id调用vod api设置媒体文件基本信息
		try
		{
			DescribeMediaInfosResponse resp = getDescribeMediaInfosResponse(trackInfoVo);
			//获取媒体文件url
			String mediaUrl = (resp.getMediaInfoSet())[0].getBasicInfo().getMediaUrl();
			//设置媒体文件url
			trackInfo.setMediaUrl(mediaUrl);
			//获取音频大小
			Long size = resp.getMediaInfoSet()[0].getMetaData().getSize();
			//设置音频大小
			trackInfo.setMediaSize(size);
			//获取音频类型
			String container = resp.getMediaInfoSet()[0].getMetaData().getContainer();
			//设置音频类型
			trackInfo.setMediaType(container);
			//获取声音媒体时长
			Float audioDuration = resp.getMediaInfoSet()[0].getMetaData().getAudioDuration();
			//设置声音媒体时长
			trackInfo.setMediaDuration(new BigDecimal(audioDuration));
		} catch (TencentCloudSDKException e)
		{
			log.error("e: ", e);
		}
		//获取当前用户专辑下的最大音频排序值, 将其+1作为新添加的音频的排序值
		Integer maxOrderNum = trackInfoMapper.selectMaxOrderNumByAlbumId(trackInfo.getAlbumId());
		//如果是音频下第一个专辑,将排序值初始化为1
		trackInfo.setOrderNum(maxOrderNum != null ? maxOrderNum + 1 : 1);
		//保存媒体文件信息
		this.save(trackInfo);
		boolean flag = true;
		//获取当前专辑信息
		AlbumInfo albumInfo = albumInfoService.getById(trackInfo.getAlbumId());
		//获取当前专辑下音频数量
		Integer oldincludeTrackCount = albumInfo.getIncludeTrackCount();
		//更新专辑下音频数量
		LambdaUpdateWrapper<AlbumInfo> albumInfoLambdaUpdateWrapper = new LambdaUpdateWrapper<AlbumInfo>().eq(AlbumInfo::getId, trackInfo.getAlbumId())
				.eq(AlbumInfo::getIncludeTrackCount, oldincludeTrackCount)
				.set(AlbumInfo::getIncludeTrackCount, oldincludeTrackCount + 1);
		boolean count = albumInfoService.update(albumInfoLambdaUpdateWrapper);
		if (!count)
		{
			//更新失败,抛出异常,数据已被修改
			throw new BaseException(ResultCodeEnum.VOD_FILE_MESSAGE_SAVE_ERROR);
		}
		//id回填,获取保存的媒体文件id
		Long trackInfoId = trackInfo.getId();
		//初始化媒体文件 '统计类型'
		TrackStat trackStat = new TrackStat();
		//TODO:统计类型：0701-播放量 0702-收藏量 0703-点赞量 0704-评论数
		for (String stat : trackStatList)
		{
			//避免id回填,影响数据的保存
			trackStat.setId(null);
			trackStat.setStatType(stat);
			trackStat.setTrackId(trackInfoId);
			trackStatMapper.insert(trackStat);
		}
	}

	@Override
	public IPage<TrackListVo> findUserTrackPage(Long page, Long limit, TrackInfoQuery trackInfoQuery) {
		//获取用户id
		Long userId = AuthContextHolder.getUserId();
		trackInfoQuery.setUserId(userId);
		//查询当前用户下的专辑
		return trackInfoMapper
				.selectUserAlbumPage(new Page<>(page, limit), trackInfoQuery);
	}

	@Override
	@Transactional
	public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) throws TencentCloudSDKException {
		//直接根据音频id修改数据,不采用先删后增
		//获取旧音频数据
		TrackInfo trackInfo = getById(trackId);
		//保存旧音频媒体文件id
		String oldTrackFileId = trackInfo.getMediaFileId();
		//更新除音频媒体属性外的vo传入的其他属性
		trackInfo.setIsOpen(trackInfoVo.getIsOpen());
		trackInfo.setCoverUrl(trackInfoVo.getCoverUrl());
		trackInfo.setTrackRichIntro(trackInfoVo.getTrackRichIntro());
		trackInfo.setTrackIntro(trackInfoVo.getTrackIntro());
		trackInfo.setTrackTitle(trackInfoVo.getTrackTitle());
		trackInfo.setUpdateTime(new Date());
		//音频媒体文件id改变,修改相关音频参数
		if (!oldTrackFileId.equals(trackInfoVo.getMediaFileId()))
		{
			DescribeMediaInfosResponse resp = getDescribeMediaInfosResponse(trackInfoVo);
			//获取媒体文件url
			String mediaUrl = resp.getMediaInfoSet()[0].getBasicInfo().getMediaUrl();
			//设置媒体文件url
			trackInfo.setMediaUrl(mediaUrl);
			//获取音频大小
			Long size = resp.getMediaInfoSet()[0].getMetaData().getSize();
			//设置音频大小
			trackInfo.setMediaSize(size);
			//获取音频类型
			String container = resp.getMediaInfoSet()[0].getMetaData().getContainer();
			//设置音频类型
			trackInfo.setMediaType(container);
			//获取声音媒体时长
			Float audioDuration = resp.getMediaInfoSet()[0].getMetaData().getAudioDuration();
			//设置声音媒体时长
			trackInfo.setMediaDuration(new BigDecimal(audioDuration));
			//删除原音频媒体文件文件
		}
		//更新数据
		updateById(trackInfo);
	}

	@Override
	public void removeTrackInfo(Long trackId) {
		//删除音频信息
		removeById(trackId);
		//删除音频相关'统计类型'
		trackStatMapper.deleteStatByTrackID(trackId);
	}

	@Override
	public IPage<AlbumTrackListVo> findAlbumTrackPage(Long albumId, Long page, Long limit) {
		//获取用户信息
		Long userId = AuthContextHolder.getUserId();
		if (userId == null)
		{
			throw new BaseException(ResultCodeEnum.LOGIN_AUTH);
		}
		Result<UserInfoVo> userInfoForFeign = userApiFeignClient.getUserInfoForFeign(userId);
		UserInfoVo userInfoVo = userInfoForFeign.getData();
		//获取专辑下声音
		IPage<AlbumTrackListVo> resultPage = trackInfoMapper.findAlbumTrackPageByAlbumId(new Page<>(page, limit), albumId);
		//获取当前专辑信息
		AlbumInfo albumInfo = albumInfoService.getAlbumInfoById(albumId);
		//获取专辑付费类型
		String payType = albumInfo.getPayType();
		//用于标记是否需要标记付费专辑, 默认为免费类型
		Boolean isNeedPay = Boolean.FALSE;
		//判断用户类型
		Integer userType = userInfoVo.getIsVip();
		//获取vip到期时间
		Date vipExpireTime = userInfoVo.getVipExpireTime();
		if (vipExpireTime != null && vipExpireTime.after(new Date()))
		{
			//vip到期,标记为普通用户
			userType = SystemConstant.NORMAL;
		}
		//判断专辑付费类型
		if (SystemConstant.ALBUM_PAY_TYPE_FREE.equals(payType))
		{
			//对专辑无处理 ....
		} else if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType))
		{
			//vip免费专辑
			if (SystemConstant.NORMAL.equals(userType))
			{
				//普通用户需要付费
				isNeedPay = Boolean.TRUE;
			}
		} else
		{
			//属于付费专辑, 两种用户都需要付费
			isNeedPay = Boolean.TRUE;
		}
		List<AlbumTrackListVo> records = resultPage.getRecords();
		//专辑免费声音数量
		Integer tracksForFree = albumInfo.getTracksForFree();
		//获取当前专辑下声音Id列表,过滤免费声音
		List<Long> filtedAlbumTrackList = records
				.stream()
				.filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
				.map(AlbumTrackListVo::getTrackId)
				.toList();
		//调用用户接口获取用户在当前专辑下购买的专辑
		Result<Map<Long, Integer>> isPaidTrackResult = userApiFeignClient.userIsPaidTrack(albumId, filtedAlbumTrackList);
		Map<Long, Integer> isPaidTrack = isPaidTrackResult.getData();
		//对需要付费的专辑进行处理
		if (Boolean.TRUE.equals(isNeedPay) && !CollectionUtils.isEmpty(records))
		{
			if (isPaidTrack == null)
			{
				for (AlbumTrackListVo record : records)
				{
					record.setIsShowPaidMark(Boolean.TRUE);
				}
			} else
			{
				for (AlbumTrackListVo record : records)
				{
					record.setIsShowPaidMark(isPaidTrack.get(record.getTrackId()) == null
							&& record.getOrderNum() > tracksForFree
							? Boolean.TRUE : Boolean.FALSE);
				}
			}
		}
		return resultPage;
	}

	@Override
	public TrackStatVo getTrackStatVo(Long trackId) {
		return trackStatMapper.selectTrackStatVo(trackId);
	}

	@Override
	public List<Map<String, Object>> findUserTrackPaidList(Long trackId) {
		LinkedList<Map<String, Object>> resultList = new LinkedList<>();
		//获取当前声音详情
		TrackInfo trackInfo = getById(trackId);
		//获取专辑信息
		Long albumId = trackInfo.getAlbumId();
		AlbumInfoVo albumInfoVo = albumInfoService.getAlbumInfoVoById(albumId);
		//获取专辑当前后的其他声音信息
		List<TrackInfo> trackInfoList = this.list(new LambdaQueryWrapper<TrackInfo>()
				.select(TrackInfo::getId)
				.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
				.eq(TrackInfo::getAlbumId, albumId));
		//获取用户购买声音
		Result<Map<Long, Integer>> isPaidTrack = userApiFeignClient.userIsPaidTrack(albumId, trackInfoList.stream()
				.map(TrackInfo::getId).toList());
		Map<Long, Integer> isPaidTrackData = isPaidTrack.getData();
		//过滤购买的声音
		if (isPaidTrackData != null)
			trackInfoList = trackInfoList.stream()
					.filter(trackInfo1 -> isPaidTrackData.get(trackInfo1.getId()) == null)
					.toList();
		int size = trackInfoList.size();
		//本集
		{
			HashMap<String, Object> map = new HashMap<>();
			map.put("name", "本集");
			map.put("price", albumInfoVo.getPrice());
			map.put("trackCount", 1);
			resultList.add(map);
		}
		//批量添加以10为单位集数
		Stack<HashMap> stack = new Stack<>();
		while ((size / 10) > 0)
		{
			HashMap<String, Object> map = new HashMap<>();
			map.put("name", "后" + (size / 10) * 10 + "集");
			map.put("price", albumInfoVo.getPrice().multiply(BigDecimal.valueOf((size / 10) * 10)));
			map.put("trackCount", (size / 10) * 10);
			size -= 10;
			stack.add(map);
		}
		//使用栈控制集数顺序
		while (!stack.isEmpty()){
			resultList.add(stack.peek());
			stack.pop();
		}
		{
			HashMap<String, Object> map = new HashMap<>();
			map.put("name", "后" + trackInfoList.size() + "集");
			map.put("price", albumInfoVo.getPrice().multiply(BigDecimal.valueOf(trackInfoList.size())));
			map.put("trackCount", trackInfoList.size());
			resultList.add(map);
		}
		return resultList;
	}

	@Override
	public List<TrackInfo> getOrderTrackInfoList(Long itemId, Integer trackCount) {
		//获取用户信息
		Long userId = AuthContextHolder.getUserId();
		if (userId == null)
		{
			throw new BaseException(ResultCodeEnum.LOGIN_AUTH);
		}
		Result<UserInfoVo> userInfoForFeign = userApiFeignClient.getUserInfoForFeign(userId);
		UserInfoVo userInfoVo = userInfoForFeign.getData();
		//获取专辑下声音
		TrackInfo trackInfo = trackInfoMapper.selectById(itemId);
		//获取声音下专辑id
		Long albumId = trackInfo.getAlbumId();
		//获取当前声音后的所有声音
		List<TrackInfo> trackInfoList = list(new LambdaQueryWrapper<TrackInfo>()
				.eq(TrackInfo::getAlbumId, albumId)
				.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum()));
		//调用用户接口获取用户在当前专辑下购买的专辑
		Result<Map<Long, Integer>> isPaidTrackResult = userApiFeignClient.userIsPaidTrack(albumId,
				trackInfoList.stream().map(TrackInfo::getId).toList());
		Map<Long, Integer> isPaidTrackData = isPaidTrackResult.getData();
		//获取当前专辑下声音Id列表,过滤当前用户购买的声音,并且获取过滤后的前十张
		if (isPaidTrackData != null)
			trackInfoList = trackInfoList.stream()
					.filter(trackInfo1 -> isPaidTrackData.get(trackInfo1.getId()) == null)
					.sorted(Comparator.comparing(TrackInfo::getOrderNum))
					.limit(10)
					.toList();
		return trackInfoList;
	}

	@NotNull
	private VodClient getVodClient() {
		Credential cred = new Credential(vodProperties.getSecretId(), vodProperties.getSecretKey());
		// 实例化一个http选项，可选的，没有特殊需求可以跳过
		HttpProfile httpProfile = new HttpProfile();
		httpProfile.setEndpoint("vod.tencentcloudapi.com");
		// 实例化一个client选项，可选的，没有特殊需求可以跳过
		ClientProfile clientProfile = new ClientProfile();
		clientProfile.setHttpProfile(httpProfile);
		// 实例化要请求产品的client对象,clientProfile是可选的
		return new VodClient(cred, vodProperties.getStorageRegion(), clientProfile);
	}

	private DescribeMediaInfosResponse getDescribeMediaInfosResponse(TrackInfoVo trackInfoVo) throws TencentCloudSDKException {
		// 创建临时密钥
		VodClient client = getVodClient();
		// 实例化一个请求对象,每个接口都会对应一个request对象
		DescribeMediaInfosRequest req = new DescribeMediaInfosRequest();
		req.setFileIds(new String[]{trackInfoVo.getMediaFileId()});
		// 返回的resp是一个DescribeMediaInfosResponse的实例，与请求对象对应
		return client.DescribeMediaInfos(req);
	}


	void deleteVodTrack(String fileId) {
		try
		{
			VodClient client = getVodClient();
			// 实例化一个请求对象,每个接口都会对应一个request对象
			DeleteMediaRequest req = new DeleteMediaRequest();
			req.setFileId(fileId);
			// 返回的resp是一个DeleteMediaResponse的实例，与请求对象对应
			DeleteMediaResponse resp = client.DeleteMedia(req);
			// 输出json格式的字符串回包
			System.out.println(AbstractModel.toJsonString(resp));
		} catch (TencentCloudSDKException e)
		{
			log.error("e: ", e);
		}
	}

}
